home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Celestin Apprentice 5
/
Apprentice-Release5.iso
/
Source Code
/
C
/
Snippets
/
Stuart's Tech Notes
/
ATP sample code.c
< prev
next >
Wrap
C/C++ Source or Header
|
1994-12-12
|
9KB
|
288 lines
/* (C) 1992 Stuart Cheshire <cheshire@cs.stanford.edu>
From: Stuart Cheshire <cheshire@cs.stanford.edu>
Subject: Re: Looking for some sample appletalk ATP code...
Date: Wed, 2 Sep 92 18:11:08 GMT
In article <1992Sep1.033635.28604@sunb10.cs.uiuc.edu> Alex Bratton,
bratton@sparc3.cs.uiuc.edu writes:
>If you have some sample code (ATP) that opens, registers, and dumps some
>data, I'd really appreciate seeing it. This has been bugging me for a while
>and I think I need to look at some working code to see what I'm missing.
Here is some sample code, which opens and registers an ATP socket.
It could be used to form the basis of a server which will accept
calls from clients and generate responses. (The code to make the
ATP call from the client is not included -- that is the easy part.)
Notes:
The code is written for Think C 5.
My style of coding is to start with main() at the bottom, and then
work UP the file calling routines defined above. This is basically
because I want full type checking but I'm too lazy to write and
maintain prototypes for every function so I avoid it by defining
every routine before I call it. I hope this doesn't give you headaches.
Registering the name "xxxx.xx" (net.node) might seem to invite name
conflicts with other programs, but remember that the type is also
registered: "xxxx.xx:ATP tester@*" so it WILL be unique.
*/
#include <Traps.h>
#include <GestaltEqu.h>
#include <Folders.h>
#include <AppleTalk.h>
#include "StuTypes.h"
#include "StuAppleTalk.h"
static unsigned char entity_type[] = "\pATP tester";
// Define structures to describe your requests and responses here.
typedef struct { char x; } REQUEST;
typedef struct { char y; } RESPONSE;
typedef struct { MPPParamBlock p; long *myglobals; } myMPPParamBlock;
typedef struct { ATPParamBlock p; long *myglobals; } myATPParamBlock;
typedef struct { ATQEntry e; long *myglobals; } myATQEntry;
local OSErr ErrorStatus; // if non-zero, means that the server is not running
local NamesTableEntry myNTE; // DONT TOUCH THIS -- IT'S USED CONTINUOUSLY BY NBP
local myATQEntry AppleTalkTransitionQueueEntry;
// name must be 8 characters long
local void construct_name(AddrBlock addr, unsigned char *name)
{
static unsigned char hextable[] = "0123456789ABCDEF";
name[0] = 7;
name[1] = hextable[(addr.aNet >> 12) & 0xF];
name[2] = hextable[(addr.aNet >> 8) & 0xF];
name[3] = hextable[(addr.aNet >> 4) & 0xF];
name[4] = hextable[(addr.aNet >> 0) & 0xF];
name[5] = '.';
name[6] = hextable[(addr.aNode >> 4) & 0xF];
name[7] = hextable[(addr.aNode >> 0) & 0xF];
}
/**************************************************************************************/
// This pair of routines call each other in an infinite ring. When awaitrequest
// gets an incoming request, it calls acceptrequest to dispatch a reply. After
// the reply has been sent, control returns back to awaitrequest.
local void awaitrequest(void);
local void acceptrequest(void)
{
static RESPONSE resp;
static BDSElement bds;
myATPParamBlock *atp_pb;
long *saveGptr;
asm { move.l GLOBREG, saveGptr
move.l a0, atp_pb
move.l myATPParamBlock.myglobals(a0), GLOBREG
}
// if (atp_pb->p.ATPioResult) What to do if error?
// Do whatever you want here to prepare your response...
// Note: This is an INTERRUPT TIME completion routine, which means that you
// can't allocate memory, call QuickDraw, put up dialogs to interract with
// the user etc. These things have to be done from your application's main
// event loop, or by using the notification manager.
bds.buffSize = sizeof(resp);
bds.buffPtr = (Ptr)&resp;
bds.dataSize = 0;
bds.userBytes = 0;
atp_pb->p.ATPioCompletion = (ProcPtr)awaitrequest;
atp_pb->p.ATPatpFlags = atpEOMvalue;
atp_pb->p.ATPbdsPointer = (Ptr)&bds;
atp_pb->p.ATPnumOfBuffs = 1;
atp_pb->p.ATPbdsSize = 1;
PSendResponse(&atp_pb->p, TRUE);
asm { move.l saveGptr, GLOBREG }
}
local void awaitrequest(void)
{
static REQUEST req;
myATPParamBlock *atp_pb;
long *saveGptr;
asm { move.l GLOBREG, saveGptr
move.l a0, atp_pb
move.l myATPParamBlock.myglobals(a0), GLOBREG
}
atp_pb->p.ATPioCompletion = (ProcPtr)acceptrequest;
atp_pb->p.ATPatpSocket = myNTE.nt.nteAddress.aSocket;
atp_pb->p.ATPreqLength = sizeof(req);
atp_pb->p.ATPreqPointer = (Ptr)&req;
PGetRequest(&atp_pb->p, TRUE);
asm { move.l saveGptr, GLOBREG }
}
/**************************************************************************************/
// After the name registration below (in AppleTalkStartUp) completes, this routine
// is called to check the return codes, and if all is well it calls awaitrequest();
local void register_done(void)
{
static myATPParamBlock atp;
long *saveGptr;
asm { move.l GLOBREG, saveGptr
move.l myMPPParamBlock.myglobals(a0), GLOBREG
tst.w ErrorStatus
bne.s @e
move.w OFFSET(MPPParamBlock,MPPioResult)(a0), ErrorStatus
bne.s @e
clr.w atp.p.ATPioResult
move.l GLOBREG, atp.myglobals
lea atp, a0
bsr awaitrequest
@e move.l saveGptr, GLOBREG
}
}
/**************************************************************************************/
// Startup opens the socket and registers the NBP name on the net.
// ShutDown deregisters the name and closes the socket.
// These may be called many times during the lifetime of the program,
// for instance when the PowerBook goes to sleep and then wakes up again,
// when the user unplugs the PowerBook from the network and turns AppleTalk
// off and then later re-connects it and turns AppleTalk back on, when the
// Mac is moved from an Ethernet connection to LocalTalk, or to Token Ring,
// or to ARA dial-up etc.
local OSErr AppleTalkStartUp(void)
{
if (ErrorStatus == noErr)
{
ATPParamBlock atp;
static myMPPParamBlock p;
static AddrBlock zeroaddress;
static unsigned char regname[8];
atp.ATPatpSocket = 0;
atp.ATPaddrBlock = zeroaddress;
ErrorStatus = POpenATPSkt(&atp, FALSE);
if (ErrorStatus) return(ErrorStatus);
p.p.SETSELF.newSelfFlag = TRUE;
PSetSelfSend(&p.p, FALSE); // no need to abort if this fails
myNTE.nt.nteAddress.aNet = ABusVars->sysNetNum;
myNTE.nt.nteAddress.aNode = ABusVars->sysLAPAddr;
myNTE.nt.nteAddress.aSocket = atp.ATPatpSocket;
construct_name(myNTE.nt.nteAddress, regname);
NBPSetNTE((Ptr)&myNTE,
(Ptr)regname, (Ptr)"\pMacintosh Authenticator", (Ptr)"\p*",
myNTE.nt.nteAddress.aSocket);
p.p.MPPioCompletion = (ProcPtr)register_done;
p.p.NBPinterval = 2;
p.p.NBPcount = 8;
p.p.NBPntQElPtr = (Ptr)&myNTE;
p.p.NBPverifyFlag = TRUE;
asm { move.l GLOBREG, p.myglobals }
ErrorStatus = PRegisterName(&p.p, TRUE);
}
return(ErrorStatus);
}
local void AppleTalkShutDown(void)
{
if (ErrorStatus == noErr)
{
ATPParamBlock atpb;
MPPParamBlock p;
atpb.ATPatpSocket = myNTE.nt.nteAddress.aSocket;
PCloseATPSkt(&atpb, FALSE);
p.NBPentityPtr = myNTE.nt.entityData;
PRemoveName(&p, FALSE);
}
}
local long ATalkTransition(long selector, myATQEntry *atq, long param)
{
long *saveGptr;
asm { move.l GLOBREG, saveGptr
move.l atq, a0
move.l myATQEntry.myglobals(a0), GLOBREG
cmp.l #ATTransOpen, selector
bne.s @1
bsr AppleTalkStartUp
bra.s @2
@1 cmp.l #ATTransClose, selector
bne.s @2
bsr AppleTalkShutDown
@2 move.l saveGptr, GLOBREG
clr.l d0 ; must return zero
}
}
/**************************************************************************************/
// This assembler is here because the LAPAddATQ and LAPRmvATQ calls provided by
// Apple's nAppleTalk library have a bug which crashes the system when you call them
extern pascal OSErr my_LAPAddATQ(ATQEntryPtr theATQEntry);
extern pascal OSErr my_LAPRmvATQ(ATQEntryPtr theATQEntry);
local void assembler(void)
{
asm {
extern my_LAPAddATQ:
move.w #LAddAEQ, d0
bra.s @1
extern my_LAPRmvATQ:
move.w #LRmvAEQ, d0
@1 move.l 4(sp), a0
move.l LAPMgrPtr, a1
move.l (sp)+, (sp)
jsr 2(a1)
move.l (sp)+, a0
move.w d0, (sp)
jmp (a0)
}
}
/**************************************************************************************/
// Init is used ONCE, when the program is first loaded, and
// Quit would be called ONCE, finally, if the program exits
local OSErr AppleTalkInit(void) // returns non-zero if init failed
{
short MPPRefNum;
SysEnvRec sysenvirons;
SysEnvirons(1, &sysenvirons);
ErrorStatus = OpenDriver("\p.MPP", &MPPRefNum);
if (ErrorStatus) return(ErrorStatus);
if (sysenvirons.atDrvrVersNum >= 53)
{
AppleTalkTransitionQueueEntry.e.CallAddr = (ProcPtr)ATalkTransition;
asm { move.l GLOBREG, AppleTalkTransitionQueueEntry.myglobals }
ErrorStatus = my_LAPAddATQ(&AppleTalkTransitionQueueEntry.e);
if (ErrorStatus) return(ErrorStatus);
}
return(AppleTalkStartUp());
}
local void AppleTalkQuit(void)
{
SysEnvRec sysenvirons;
SysEnvirons(1, &sysenvirons);
if (sysenvirons.atDrvrVersNum >= 53) my_LAPRmvATQ(&AppleTalkTransitionQueueEntry.e);
AppleTalkShutDown();
}